using AutoMapper;
using Tools.Common.ServiceLocator;
using Tools.Domain.Common.ConstraintSets;
using Tools.Domain.Common.Repositories.Contracts;
using Tools.Domain.Specifications.Constraints;
using Web.App.Infrastructure.CrossCuttingConcerns.Attributes;
using Webshop20.Application.Operations.Messages;
using Webshop20.Domain.Catalog.Core;
using Webshop20.Domain.Catalog.Translations.CatalogToOrders;
using Webshop20.Domain.Common.Exceptions;
using Webshop20.Domain.Customers.Core;
using Webshop20.Domain.Customers.Services.DataTransferObjects;
using Webshop20.Domain.Orders.Core;
using Webshop20.Domain.Orders.Factories.Contracts;
using Webshop20.Domain.Orders.Processes;
using Webshop20.Domain.Orders.Processes.Events;

namespace Webshop20.Application.Operations.Services
{
    public interface IInitOrderService : IService
    {
        [Transaction]
        new ISystemMessage Handle(ISystemMessage request);
    }

    public class InitOrderService : ServiceBase, IInitOrderService
    {
        private readonly IOrderTranslator orderTranslator;
        private readonly IOrderFactory orderFactory;
        private readonly IRepository<Customer> customerRepository;
        private readonly IRepository<Visitor> visitorRepository;
        private readonly IRepository<OrderProcess> orderProcessRepository;
        private readonly IRepository<Order> orderRepository;
        private readonly IServiceLocator serviceLocator;
        private IOrderProcessFactory orderProcessFactory;
        private IConstraintSetFactory constraintSetFactory;

        public InitOrderService(IOrderTranslator orderTranslator, IOrderFactory orderFactory, IRepository<Customer> customerRepository, IRepository<OrderProcess> orderProcessRepository, IServiceLocator serviceLocator, IRepository<Order> orderRepository, IRepository<Visitor> visitorRepository, IOrderProcessFactory orderProcessFactory, IConstraintSetFactory constraintSetFactory)
        {
            this.orderTranslator = orderTranslator;
            this.constraintSetFactory = constraintSetFactory;
            this.orderProcessFactory = orderProcessFactory;
            this.visitorRepository = visitorRepository;
            this.orderRepository = orderRepository;
            this.serviceLocator = serviceLocator;
            this.orderProcessRepository = orderProcessRepository;
            this.customerRepository = customerRepository;
            this.orderFactory = orderFactory;
        }

        public ISystemMessage Handle(ISystemMessage request)
        {
            //ToDo: Repository-Futures
            InitOrderResponse initOrderResponse;
            var initOrderRequest = (InitOrderRequest) request;


            try
            {
                var customer = customerRepository.FindById(initOrderRequest.VisitorId);
                var visitor = visitorRepository.FindById(initOrderRequest.VisitorId);
                var orderPositions = orderTranslator.convertCartItemsToPositions(visitor.Cart);
                var order = orderFactory.CreateInstance(
                                                        (CustomerInformationDTO)Mapper.Map(customer,
                                                        typeof(Customer), typeof(CustomerInformationDTO)),
                                                        orderPositions,
                                                        customer.Payment,
                                                        initOrderRequest.OrderDate);
                var orderProcess = order.Execute(orderProcessFactory, serviceLocator,
                                                 constraintSetFactory.Create<IConstraintSet<Order>>(new ExecuteAlways()));

                orderProcessRepository.Save(orderProcess as OrderProcess);
                orderRepository.Save(order);

                initOrderResponse = new InitOrderResponse(WITHOUT_DOMAIN_MESSAGE);
            }
            catch (DomainException ex)
            {
                initOrderResponse= new InitOrderResponse(ex.DomainMessage);
            }

            return initOrderResponse;
        }
    }
}